package com.example.tt_bells_v02;

import java.util.ArrayList;
import java.util.List;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.sax.StartElementListener;
import android.text.format.Time;
import android.util.Log;
import android.widget.Toast;

public class Bell extends BellInfo {
	//bell state masks
	static final int BELL_STATE_ENABLED 	= 0x01;
	static final int BELL_STATE_MUTED		= 0x02;
	static final int BELL_STATE_ERROR		= 0x04;
	static final int BELL_STATE_DONE		= 0x08;
	static final int BELL_STATE_UNDONE		= 0x10;
	static final int BELL_STATE_STOPPED		= 0x20;
	static final int BELL_STATE_CONTINUED	= 0x40;
	static final int BELL_STATE_WAIT		= 0x80;
	
	int bell_state = 0;
	String  filter_name;
	
	Time	alarm_time = new Time(Time.getCurrentTimezone());
	Time	last_alarm_time = new Time(Time.getCurrentTimezone());
	
	Context	 			bell_context;
	
	BellRec 			br;
	Bell 				selflink = this;
	
	List<BellTimePoint>	bTimePoints = new ArrayList<BellTimePoint>();
	
	int					current_periods_count; //in-work decrementing counter
	
	private void init(Context c) {
		bell_context = c;
		filter_name = this.toString();
		br = new BellRec();
		br.register(c, filter_name);
	}
	
	//Create new bell
	public Bell(Context con) {
		init(con);		
	}
	
	//Copy Bell from existing one
	public Bell(Bell fromBell) {
		init(fromBell.bell_context);
		copy(fromBell);
	}
	
	//Copy Bell from existing template
	public Bell(BellTemplate fromTemplate, Context con) {
		init(con);
	}
	
	public void setAlarmDay(Time new_day) {
		if (new_day != null) {
			alarm_time.set(new_day.monthDay, new_day.month, new_day.year);
			if (bell_type == BellInfo.BELL_TYPE_PERIODIC)
				recalcTimepoints();
		}
	}
	
	//No confirm results would be copied
	public void copy(Bell fromBell) {
		alarm_message = new String(fromBell.alarm_message);
		alarm_time.set(fromBell.alarm_time);
		alarm_time.allDay = false;
		last_alarm_time.allDay = false;
		bell_actions = fromBell.bell_actions;
		bell_state = 0;
		bell_type = fromBell.bell_type;
		icon_index = fromBell.icon_index;
		name_long = new String(fromBell.name_long);
		name_short = new String(fromBell.name_short);
		sound_index = fromBell.sound_index;
		
		switch (bell_type) {
		case BellInfo.BELL_TYPE_SINGLE: {
			//Do nothing
		break; }
		case BellInfo.BELL_TYPE_PERIODIC: {
			period_size = fromBell.period_size;
			periods_count = fromBell.periods_count;
			current_periods_count = periods_count;
			last_alarm_time.set(fromBell.last_alarm_time);
			
		break; }
		case BellInfo.BELL_TYPE_MULTIPLE: {
			
		break; }
		case BellInfo.BELL_TYPE_RANDOM: {
			
		break; }
	}
	}
	
	void activate()
	{
		Time current_time = new Time(Time.getCurrentTimezone());
		current_time.setToNow();
		
		if (current_time.before(alarm_time)) {
			bell_state |= BELL_STATE_ENABLED;
			AlarmManager am = (AlarmManager) bell_context.getSystemService(Context.ALARM_SERVICE);

			Intent intent = new Intent(filter_name);
			PendingIntent pendingIntent = PendingIntent.getBroadcast(bell_context, 0,
			 intent, PendingIntent.FLAG_CANCEL_CURRENT );
		
			Log.d("BELL:", "starting alarm manager");
			am.set(AlarmManager.RTC_WAKEUP, alarm_time.toMillis(false), pendingIntent);
		} else {
			Log.d(Tag.TAG,"current time is not before alarm time, cannot start alarm manager");
		}
	}
	
	void deactivate() {
		bell_state &= ~BELL_STATE_ENABLED;
		//bell_context.unregisterReceiver(br);
		br.unregister(bell_context);
	}
	
	public boolean isEnabled() {
		return ((bell_state & BELL_STATE_ENABLED) != 0);
	}
	
	public boolean isMuted() {
		return ((bell_state & BELL_STATE_MUTED) != 0);
	}
	
	public boolean isError() {
		return ((bell_state & BELL_STATE_ERROR) != 0);
	}
	
	void recalcTimepoints() { //recalculate last alarm time for periodic bell
		if (bell_type == BellInfo.BELL_TYPE_PERIODIC) {
			BellTimePoint btp;
			long lat = alarm_time.toMillis(false); //?true causes illegal argument exception with allday=true...
			long step = (60*getHour(period_size) + getMinute(period_size))*60000;
			
			bTimePoints.clear();
			for (int i=0; i<periods_count; i++) {
				btp = new BellTimePoint();
				btp.time_planned.set(lat);
				bTimePoints.add(btp);
				lat+=step;
			}
			
			//last point
			btp = new BellTimePoint();
			btp.time_planned.set(lat);
			bTimePoints.add(btp);
			last_alarm_time.set(lat);
			Log.d(Tag.TAG,"recalcTimepoints");
		}
	}

	public void activateNextTimepoint(int cur_pos, int state_if_stop) {
		if (cur_pos<(selflink.periods_count-1)) { //has next
			BellTimePoint btp = selflink.bTimePoints.get(cur_pos);
			//BellTimePoint btp = selflink.bTimePoints.get(cur_pos+1);
			long step = (60*getHour(period_size) + getMinute(period_size))*60000;
			long newplan = btp.time_confirmed.toMillis(false) + step;
			selflink.alarm_time.set(newplan);
			//TODO: maybe recalc all plans?
			//selflink.alarm_time.set(btp.time_confirmed);
			selflink.activate();
		} else { //no next timepoints
			selflink.bell_state |= state_if_stop;
			selflink.deactivate();
		}
	}
	
	public void setTimepointConfirmTime(int point_pos, int confirm_state) {
		BellTimePoint btp = selflink.bTimePoints.get(point_pos);
		if (btp != null) {
			btp.time_confirmed.setToNow();
			btp.confirm_type = confirm_state;
			int mdiff = DayCompare.getMinutesDiff(btp.time_happened, btp.time_confirmed);
			btp.minutes_shift += mdiff;
		}
	}
	
	//-------------------------------------------------------------------DATABASE TOOLS
	
	void PutIntoDB() {
		
	}
	
	
	//-------------------------------------------------------------------RECEIVER
	
	//TODO: maybe "walkthrough-and-maybe-confirm" bell needed:
	//switch to next automatically, but starts confirm dialog
	
	public class BellRec extends BroadcastReceiver {
		boolean is_registered = false;
		
		@Override
		public void onReceive(Context context, Intent intent) {
			boolean do_call_confirm = false;
			int pos = 0;
			Toast.makeText(context, alarm_message, Toast.LENGTH_SHORT).show();
			Log.d("BELL: ", alarm_message);
			switch (selflink.bell_type) {
				case BellInfo.BELL_TYPE_PERIODIC: {
					//Update BellTimePoint and call ConfirmAlarm if needed
					for (pos=0; pos<selflink.periods_count; pos++) {
						BellTimePoint btp = selflink.bTimePoints.get(pos);
						if (selflink.alarm_time.toMillis(false) == btp.time_planned.toMillis(false)) {
							btp.time_happened.setToNow();
							btp.is_happened = true;
							if ((selflink.bell_actions & BellInfo.BELL_ACTION_CONFIRM) != 0) {
								do_call_confirm = true;
							} else {
								activateNextTimepoint(pos,BELL_STATE_DONE);
							}
							break;
						}
					}
				break; }
			}
			
			if (do_call_confirm) {
				Intent aaa = new Intent(context,ActivityConfirmAlarm.class);
				aaa.putExtra("bell_id", selflink.id);
				aaa.putExtra("btp_pos", pos);
				aaa.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				aaa.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
				context.startActivity(aaa);
			}
		};

		public void register(Context context, String filter_name) {
			if ((context != null) && (is_registered == false)) {			
				IntentFilter filter = new IntentFilter(filter_name);
				context.registerReceiver(this, filter);
				is_registered = true;
			}
		}
		
		public void unregister(Context context) {
			if ((context != null) && (is_registered == true)) {
				context.unregisterReceiver(this);
				is_registered = false;
			}
		}
	}
	
}
